#ifndef _M_CONSUMER_H_
#define _M_CONSUMER_H_

#include <iostream>
#include <google/protobuf/map.h>
#include <string>
#include <vector>
#include <cassert>
#include <sstream>
#include <functional>
#include <mutex>
#include <unordered_map>
#include <string>

#include "../mqcommon/mqProto.pb.h"
#include "../mqcommon/logger.hpp"
#include "../mqcommon/helper.hpp"

namespace MyRabbitMQ
{
    namespace NSConsumer
    {
        using Callback = std::function<void(const std::string&, const protoMQ::BaseProperties*,const std::string&)>;
    };
    //消费者类
    class Consumer
    {
    public:
        using ptr = std::shared_ptr<Consumer>;

        Consumer()
        :m_name("nullptr")
        ,m_subscriptionQueue("parent_nullptr")
        ,m_autoAck(false)
        ,m_callback(nullptr)
        {
            LOG(logLevel::INFO) << "创建了空消费者" << std::endl;
        }

        Consumer(const std::string& name, const std::string& qname, bool autoAck ,
        const MyRabbitMQ::NSConsumer::Callback& callback)
        :m_name(name)
        ,m_subscriptionQueue(qname)
        ,m_autoAck(autoAck)
        ,m_callback(std::move(callback))
        {
            LOG(logLevel::INFO) << "创建了消费者: " << this->m_name << std::endl;
        }
        
        ~Consumer()
        {
            LOG(logLevel::INFO) << "删除了消费者: " << this->m_name << std::endl;
        }

    public:
        std::string m_name;
        std::string m_subscriptionQueue;
        bool m_autoAck;
        MyRabbitMQ::NSConsumer::Callback m_callback;
    };
    
    //消费者管理结构 以队列为单元
    class QueueConsumer
    {
    public:
        using ptr = std::shared_ptr<QueueConsumer>;

        QueueConsumer(const std::string& qname)
        :m_name(qname)
        ,m_count(0)
        {}

        //新增消费者
        Consumer::ptr insert(const std::string& cname, bool isAutoAck ,const MyRabbitMQ::NSConsumer::Callback& callback)
        {
            std::unique_lock<std::mutex>(m_mtx);

            //先检查有没有重复的 ,如果有重复的则不用新增
            if(this->exists(cname))
            {
                return this->getByName(cname);
            }            

            //没有, 进行添加逻辑
            Consumer::ptr item = std::make_shared<Consumer>(cname,m_name,isAutoAck,callback);

            m_consumers.push_back(item);
            ++m_count;
            return item; 
        }

        //删除消费者
        void remove(const std::string& cname)
        {
            std::unique_lock<std::mutex>(m_mtx);

            for(auto it = m_consumers.begin(); it != m_consumers.end(); ++it)
            {
                if(it->get()->m_name == cname)
                {
                    m_consumers.erase(it);
                    --m_count;
                    return;
                }    
            }
            return;
        }
        //RR轮转获取消费者进行消费
        Consumer::ptr RRChoose()
        {
            std::unique_lock<std::mutex>(m_mtx);

            //如果消费者队列不存在消费者则返回
            if(this->empty())
            {
                return Consumer::ptr();
            }

            //获取轮转下标
            int idx = m_count % m_consumers.size();
            ++m_count;

            return m_consumers[idx];
        }

        //判断消费者队列是否为空
        bool empty()
        {
            std::unique_lock<std::mutex>(m_mtx);
            return m_consumers.size() == 0;
        }

        //判断是否存在特定消费者
        bool exists(const std::string& cname)
        {
            std::unique_lock<std::mutex>(m_mtx);
            for(auto& f : m_consumers)
            {
                if(f->m_name == cname) return true;
            }

            return false;
        }

        //根据名称获取指定消费者
        Consumer::ptr getByName(const std::string& cname)
        {
            std::unique_lock<std::mutex>(m_mtx);
            for(auto& f : m_consumers)
            {
                if(f->m_name == cname) return f;
            }

            return Consumer::ptr();
        }

        //清理队列消费者
        void clear()
        {
            std::unique_lock<std::mutex>(m_mtx);
            m_consumers.clear();
            m_count = 0;
        }

    private:
        std::mutex m_mtx;
        std::string m_name; //队列名称
        std::vector<Consumer::ptr> m_consumers; // 队列下的消费者
        size_t m_count; //RR轮转计数序号
    };

    //消费者管理结构 整体管理
    class ConsumerManager
    {
    public:
        using ptr = std::shared_ptr<ConsumerManager>;

        ConsumerManager(){}

        //添加消费者队列管理单元
        void declareQueueConsumer(const std::string& qname)
        {
            //加锁
            std::unique_lock<std::mutex>(m_mtx);

            //判断是否重复
            if(m_consumers.find(qname) != m_consumers.end())
            {
                return;
            }

            //需要进行添加
            QueueConsumer::ptr item = std::make_shared<QueueConsumer>(qname);
            m_consumers.insert(std::make_pair(qname,item));

        }

        //删除消费者队列管理单元
        void deleteQueueConsumer(const std::string& qname)
        {
            //加锁
            std::unique_lock<std::mutex>(m_mtx);

            //判断是否存在
            if(m_consumers.find(qname) == m_consumers.end())
            {
                return;
            }

            //存在则删除
            m_consumers.erase(qname);
        }

        //向指定消费者队列管理单元新增消费者
        Consumer::ptr insertConsumer(const std::string& cname, const std::string& qname, bool isAutoAck,
        const NSConsumer::Callback& cb)
        {
            QueueConsumer::ptr tmp;
            {
                //加锁
                std::unique_lock<std::mutex>(m_mtx);

                //判断管理单元是否存在,不存在无法插入
                auto it = m_consumers.find(qname);
                if(it == m_consumers.end())
                {
                    LOG(logLevel::ERROR) << "执行失败:队列管理单元" << qname << "不存在" << std::endl;
                    return Consumer::ptr();
                } 

                tmp = it->second;
            }
            return tmp->insert(cname,isAutoAck,cb);
        }

        //从指定消费者队列管理单元删除消费者
        void deleteConsumer(const std::string& qname, const std::string& cname)
        {
            QueueConsumer::ptr tmp;
            {
                //加锁
                std::unique_lock<std::mutex>(m_mtx);

                //判断管理单元是否存在,不存在无法删除
                auto it = m_consumers.find(qname);
                if(it == m_consumers.end())
                {
                    LOG(logLevel::ERROR) << "执行失败:队列管理单元" << qname << "不存在" << std::endl;
                    return;
                } 

                tmp = it->second;
            }

            tmp->remove(cname);
        }

        //从指定消费者队列管理单元获取消费者
        Consumer::ptr getConsumer(const std::string& qname)
        {
           // LOG(logLevel::normal) << "getConsumer" << qname.c_str() << std::endl;
            QueueConsumer::ptr tmp;
            {
                //加锁
                std::unique_lock<std::mutex>(m_mtx);

                //判断管理单元是否存在,不存在无法获取
                auto it = m_consumers.find(qname);
                if(it == m_consumers.end())
                {
                    LOG(logLevel::ERROR) << "执行失败:队列管理单元" << qname << "不存在" << std::endl;
                    return Consumer::ptr();
                } 

                tmp = it->second;
            }

            return tmp->RRChoose();
        }

        //判断是否存在消费者队列管理单元
        bool empty()
        {
            //加锁
            std::unique_lock<std::mutex>(m_mtx);
            return m_consumers.empty();
        }

        //判断指定消费者是否存在
        bool exists(const std::string& qname, const std::string& cname)
        {
            //加锁
            std::unique_lock<std::mutex>(m_mtx);
            if(m_consumers.find(qname) == m_consumers.end()) return false;
            if(!m_consumers[qname]->exists(cname)) return false;

            return true;
        }

        //清理
        void clear()
        {
            //加锁
            std::unique_lock<std::mutex>(m_mtx);
            m_consumers.clear();   
        }

    private:
        std::mutex m_mtx;
        std::unordered_map<std::string, QueueConsumer::ptr> m_consumers;       
    };

};

#endif